( function( w ) {

	XMLHttpRequest.prototype.sendAsBinary = XMLHttpRequest.prototype.sendAsBinary || function( datastr ) {
		var ords = Array.prototype.map.call( datastr, function( x ) {
			return x.charCodeAt( 0 ) & 0xff;
		}), ui8a = new Uint8Array( ords );
		this.send( ui8a.buffer );
	};

	File.prototype.getAsBinary = File.prototype.getAsBinary || function() {
		if( typeof this.binaryData == 'undefined' ) {
			var reader = new FileReader(), me = this;
			reader.onload = function( e ) {
				me.binaryData = e.target.result;
			};
			( typeof reader.readAsBinaryString != 'undefined' ) ? reader.readAsBinaryString( this ) : reader.readAsArrayBuffer( this );
		} else {
			return this.binaryData;
		}
	};

	var Uploader = function( options ) {
		this.settings = {
			fieldName : 'fileElement',
			action : false,
			file : false,
			success : function( resp ) { alert( resp ); },
			error : function() { alert( 'ajax error' ); },
			progress : function() {},
			headers : {},
			fields : {}
		};

		options = options || {};
		for( var prop in this.settings ) {
			if( typeof options[ prop ] != 'undefined' ) {
				this.settings[ prop ] = options[ prop ];
			}
		}
		if( !( this.settings.file instanceof File ) ) {
			if( console.log ) {
				console.log( 'Cannot upload this file!' );
			} else {
				alert( 'Cannot upload this file!' );
			}
		}
		this.settings.action = this.settings.action || document.location.href;
		this.settings.progress = typeof this.settings.progress == 'function' ? this.settings.progress : function() {};
		this.headers = typeof this.settings.headers == 'object' ? this.settings.headers : {};
		this.settings.fields = typeof this.settings.fields == 'object' ? this.settings.fields : {};
		this.settings.fieldName = this.settings.fieldName || 'fileElement';
		var xhr = new XMLHttpRequest();
		this.upload( xhr );
	};

	Uploader.prototype = {
		supports : {
			'file' : typeof File,
			'file_reader' : typeof FileReader,
			'binay_xhr' : typeof XMLHttpRequest.prototype.sendAsBinary
		}, generateBoundary : function() {
			return "AJAX-----------------------" + ( new Date() ).getTime();
		}, buildMessage : function( boundary ) {
			var CRLF = "\r\n", parts = [];
			parts.push( 'Content-Disposition: form-data; name="' + this.settings.fieldName + '"; filename="'+ this.settings.file.name + '"' + CRLF + 'Content-Type: ' + this.settings.file.type + CRLF + CRLF + this.settings.file.getAsBinary() + CRLF );
			for( var name in this.settings.fields ) {
				if( typeof this.settings.fields[ name ] != 'function' ) {
					parts.push( 'Content-Disposition: form-data; name="' + name + '"' + CRLF + CRLF + this.settings.fields[ name ] + CRLF );
				}
			}
			return "--" + boundary + CRLF + parts.join( "--" + boundary + CRLF ) + "--" + boundary + "--" + CRLF;
		}, upload : function( xhr ) {
			var boundary = this.generateBoundary();
			xhr.uploader = this;
			xhr.open( "POST", this.settings.action, true );
			xhr.onreadystatechange = function() {
				if( this.readyState === 4 ) {
					if( this.status == 200 ) {
						this.uploader.settings.success( this.responseText, this.uploader.settings.file );
					} else {
						this.uploader.settings.error( this.responseText, this.uploader.settings.file );
					}
				}
			};
			
			if( typeof xhr.onuploadprogress == 'undefined' ) {
				xhr.upload.xhr = xhr;
				xhr.upload.onprogress = function( evt ) {
					if( evt.lengthComputable ) {
						this.xhr.uploader.settings.progress( ( ( evt.loaded / evt.total ) * 100 ).toFixed( 0 ), this.xhr.uploader.settings.file, evt );
					} else {
						this.xhr.uploader.settings.progress( 0, this.xhr.uploader.settings.file, evt );
					}
				};
			} else {
				xhr.onuploadprogress = function( evt ) {
					if( evt.lengthComputable ) {
						this.uploader.settings.progress( ( ( evt.loaded / evt.total ) * 100 ).toFixed( 0 ), this.uploader.settings.file, evt );
					} else {
						this.uploader.settings.progress( 0, this.uploader.settings.file, evt );
					}
				};
			}
			xhr.upload.file = this.settings.file;
			xhr.setRequestHeader( 'Content-Type', 'multipart/form-data' );
			for( var header in this.settings.headers ) {
				if( typeof this.settings.headers[ header ] != 'function' ) {
					xhr.setRequestHeader( header, this.settings.headers[ header ] );
				}
			}
			xhr.setRequestHeader( 'X-File-Name', this.settings.file.name );
			xhr.setRequestHeader( 'X-File-Size', this.settings.file.size );
			xhr.setRequestHeader( 'X-File-Type', this.settings.file.type );
			xhr.send( this.settings.file );
		}
	};

	var Worker = function() {
		return this.init();
	};

	Worker.prototype = {
		extend : function() {
			if( arguments.length == 1 ) {
				arguments = [ this, arguments[ 0 ] ];
			}
			for( var i = 0; i < arguments.length; i++ ) {
				if( i == 0 ) {
					continue;
				}
				console.log( arguments );
				if( typeof arguments[ i ] == 'object' ) {
					for( var j in arguments[ i ] ) {
						arguments[ 0 ][ j ] = arguments[ i ][ j ];
					}
				}
				return arguments[ 0 ];
			}
		}, bypass : function( callback ) {
			var values = [], me = this;
			for( var i = 0; i < arguments.length; i++ ) {
				if( i > 0 ) {
					values.push( arguments[ i ] );
				}
			}
			return function( values ) {
				callback.call( me, values );
			};
		}, bind : function( elements, event, callback ) {
			if( typeof elements.length == 'undefined' ) {
				elements = [ elements ];
			}
			for( var i = 0, l = elements.length; i < l; i++  ) {
				var element = elements[ i ];
				if( window.addEventListener) {
					element.addEventListener( event, callback, false );
				} else if( window.attachEvent ) {
					element.attachEvent( 'on' + event, callback );
				} else {
					var oldEventHandler = typeof element[ 'on' + event ] == 'function' ? element[ 'on' + event ] : this.empty;
					element[ 'on' + event ] = function( e ) {
						oldEventHandler( e );
						callback( e );
					}
				}
			}
			return this;
		}, init : function() {
			this.bind( window, 'error', function( err ) {
				if( debugMode ) {
					return;
				} else {
					err.preventDefault();
					var logImg = new Image();
					logImg.src = '/app/log/?msg=' + encodeURIComponent( err.message + ' on line number ' + err.lineno + ' on file ' + err.filename );
					return true;
				}
			});
			this.bind( document, 'readystatechange', this.bypass( function() {
				console.log( 'document status', document.readyState );
				if( document.readyState == 'complete' ) {
					this.domReady = true;
					this.readyEvents();
				}
			}));
			return this;
		}, empty : function() {
			return this;
		}, trigger : function( element, eventType ) {
			var event;
			if( document.createEvent ) {
				event = document.createEvent( 'HTMLEvents' );
				event.initEvent( eventType, true, true );
			} else {
				event = document.createEventObject();
				event.eventType = eventType;
			}
			if( document.createEvent ) {
				element.dispatchEvent( event );
			} else {
				element.fireEvent( 'on' + event.eventType, event );
			}
			if( typeof element[ eventType ] == 'function' ) {
				element[ eventType ]();
			}
		}, readyEvents : function() {
			this.bind( document.getElementsByClassName( 'videoFile' ), 'change', function() {
				var me = this;
				new Uploader({
					file : me.files[ 0 ],
					fieldName : me.name,
					success : function( resp, file ) {
						var progressBar = me.parentNode.previousElementSibling.getElementsByTagName( 'progress' )[ 0 ], resultDiv = document.getElementById( 'resultDiv' );
						progressBar.value = 100;
						progressBar.nextElementSibling.innerHTML = 'Completed';
						me.value = '';
						resultDiv.style.color = '';
						resultDiv.innerHTML = resp;
					}, error : function( resp, file ) {
						var progressBar = me.parentNode.previousElementSibling.getElementsByTagName( 'progress' )[ 0 ], resultDiv = document.getElementById( 'resultDiv' );
						progressBar.value = 0;
						progressBar.nextElementSibling.innerHTML = 'Error occured while uploading ...';
						me.value = '';
						resultDiv.style.color = 'red';
						resultDiv.innerHTML = resp;
					}, progress : function( percent, file ) {
						var progressBar = me.parentNode.previousElementSibling.getElementsByTagName( 'progress' )[ 0 ];
						progressBar.value = percent;
						progressBar.setAttribute( 'title', percent + '% complete ...' );
						progressBar.nextElementSibling.innerHTML = percent == 100 ? 'Applying watermark and uploading to youtube ...' : percent + '%';
					}
				});
			});
			var resultDiv = document.createElement( 'div' );
			resultDiv.id = 'resultDiv';
			document.body.appendChild( resultDiv );
		}
	};
	w.Worker = new Worker();
})( window );